package com.pro01.apirednote.controller;

import com.pro01.apirednote.dto.ContentRequest;
import com.pro01.apirednote.dto.ContentResponse;
import com.pro01.apirednote.dto.ContentWithFilesResponse;
import com.pro01.apirednote.mapper.ContentFileMapper;
import com.pro01.apirednote.mapper.ContentMapper;
import com.pro01.apirednote.pojo.Content;
import com.pro01.apirednote.pojo.ContentFile;
import com.pro01.apirednote.pojo.PageResult;
import com.pro01.apirednote.pojo.Result;
import com.pro01.apirednote.service.CacheService;
import com.pro01.apirednote.service.ContentService;
import com.pro01.apirednote.service.ElasticsearchService;
import com.pro01.apirednote.utils.TokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/contents")
@RequiredArgsConstructor
public class ContentController {

    private final ContentService contentService;
    private final ContentFileMapper contentFileMapper;
    private final ElasticsearchService elasticsearchService;
    private final CacheService cacheService;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ContentMapper contentMapper;
    
    private static final String SEARCH_CACHE_PREFIX = "search:";
    private static final String CONTENT_CACHE_PREFIX = "content:detail:";
    private static final String CONTENT_FILES_CACHE_PREFIX = "content:files:";
    
    // 发布内容
    @PostMapping("/create")
    public Result<?> createContent(@RequestBody ContentRequest req, HttpServletRequest request) {
        Long userId = TokenUtil.getUserId(request);
        return contentService.createContent(userId, req);
    }

    // 修改内容
    @PutMapping("/{contentId}/edit")
    public Result<?> editContent(@PathVariable Long contentId,
                                 @RequestBody ContentRequest req,
                                 HttpServletRequest request) {
        Long userId = TokenUtil.getUserId(request);
        return contentService.editContent(userId, contentId, req);
    }

    // 删除内容
//    @DeleteMapping("/{contentId}/delete")
//    public Result<?> deleteContent(@PathVariable Long contentId, HttpServletRequest request) {
//        Long userId = TokenUtil.getUserId(request);
//        return contentService.deleteContent(userId, contentId);
//    }
    @DeleteMapping("/{contentId}/delete")
    public Result<?> deleteContent(@PathVariable Long contentId, HttpServletRequest request) {
        Long userId = TokenUtil.getUserId(request);
        String role = TokenUtil.getRole(request);
        return contentService.deleteContentWithRole(userId, contentId, role);
    }

    // 查看我发布的内容
    @GetMapping("/my")
    public Result<PageResult<ContentWithFilesResponse>> getMyContent(@RequestParam(defaultValue = "1") int pageNum,
                                                                     @RequestParam(defaultValue = "10") int pageSize,
                                                                     HttpServletRequest request) {
        Long userId = TokenUtil.getUserId(request);
        return contentService.getMyContent(userId, pageNum, pageSize);
    }

    // 查看内容详情
    @GetMapping("/{contentId}")
    public Result<ContentWithFilesResponse> getContentDetail(@PathVariable Long contentId,
                                                             HttpServletRequest request) {
        Long userId = null;
        try {
            userId = TokenUtil.getUserId(request);
        } catch (Exception ignored) {
            // 用户未登录，忽略异常
        }
        return contentService.getContentDetail(contentId, userId);
    }

    // 根据标题关键字搜索内容
    @GetMapping("/search")
    public Result<PageResult<Content>> searchContent(
            @RequestParam String keyword,
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize) {
        
        // 尝试从缓存获取搜索结果
        String cacheKey = cacheService.generateSearchKey("db", keyword, pageNum, pageSize);
        PageResult<Content> cachedResult = cacheService.getCachedSearchResult(cacheKey);
        
        if (cachedResult != null) {
            log.info("使用缓存的数据库搜索结果: {}", cacheKey);
            return Result.success(cachedResult);
        }
        
        // 未命中缓存，执行数据库搜索
        Result<PageResult<Content>> result = contentService.searchByTitle(keyword, pageNum, pageSize);
        
        // 如果搜索成功，缓存结果
        if (result.getCode() == 200 && result.getData() != null) {
            cacheService.cacheSearchResult(cacheKey, result.getData(), 300); // 缓存5分钟
        }
        
        return result;
    }

    // 使用ElasticSearch进行全文搜索
    @GetMapping("/es/search")
    public Result<PageResult<ContentWithFilesResponse>> searchContentByES(
            @RequestParam String keyword,
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize) {
        // 先从ES获取内容
        Result<PageResult<Content>> esResult = elasticsearchService.searchContent(keyword, pageNum, pageSize);
        
        if (esResult.getCode() != 200) {
            return Result.error(esResult.getMessage());
        }
        
        // 转换结果为包含文件URL的响应
        PageResult<Content> pageResult = esResult.getData();
        List<Content> contentList = pageResult.getRecords();
        List<ContentWithFilesResponse> responseList = new ArrayList<>();
        
        // 为每个内容获取对应的文件URL
        for (Content content : contentList) {
            List<ContentFile> files = contentFileMapper.selectByContentId(content.getId());
            List<String> fileUrls = files.stream()
                    .map(ContentFile::getFileUrl)
                    .collect(Collectors.toList());
            
            // 使用工厂方法转换为ContentWithFilesResponse
            ContentWithFilesResponse response = ContentWithFilesResponse.fromContent(content, fileUrls);
            responseList.add(response);
        }
        
        PageResult<ContentWithFilesResponse> responsePageResult = new PageResult<>(
                pageResult.getTotal(), responseList);
        
        return Result.success(responsePageResult);
    }

    // 获取全部内容列表（包含文件URL）
//    @GetMapping("/list")
//    public Result<PageResult<ContentResponse>> getAllContent(
//            @RequestParam(defaultValue = "1") int pageNum,
//            @RequestParam(defaultValue = "10") int pageSize) {
//
//        Result<PageResult<Content>> result = contentService.getAllContent(pageNum, pageSize);
//
//        if (result.getCode() != 200) {
//            return Result.error(result.getMessage());
//        }
//
//        PageResult<Content> pageResult = result.getData();
//        List<Content> contentList = pageResult.getRecords();
//        List<ContentResponse> responseList = new ArrayList<>();
//
//        // 为每个内容获取对应的文件URL并转换为ContentResponse
//        for (Content content : contentList) {
//            List<ContentFile> files = contentFileMapper.selectByContentId(content.getId());
//            List<String> fileUrls = files.stream()
//                    .map(ContentFile::getFileUrl)
//                    .collect(Collectors.toList());
//
//            ContentResponse response = ContentResponse.fromContent(content, fileUrls);
//            responseList.add(response);
//        }
//
//        PageResult<ContentResponse> responsePageResult = new PageResult<>(
//                pageResult.getTotal(), responseList);
//
//        return Result.success(responsePageResult);
//    }
    @GetMapping("/list")
    public Result<PageResult<ContentWithFilesResponse>> listContents(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize) {
        PageResult<ContentWithFilesResponse> pageResult = contentService.listContents(pageNum, pageSize);
        return Result.success(pageResult);
    }

    // 获取指定内容点赞数量
    @GetMapping("/{contentId}/like-count")
    public Result<Integer> getLikeCount(@PathVariable Long contentId) {
        return contentService.getLikeCount(contentId);
    }

    // 获取推荐内容（按点赞数排序）
//    @GetMapping("/recommended")
//    public Result<PageResult<ContentWithFilesResponse>> getRecommendedContent(
//            @RequestParam(defaultValue = "1") int pageNum,
//            @RequestParam(defaultValue = "10") int pageSize) {
//        return contentService.getRecommendedContent(pageNum, pageSize);
//    }
    @GetMapping("/recommend")
    public Result<PageResult<ContentWithFilesResponse>> recommendContents(
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize,
            HttpServletRequest request) {

        Long userId = null;
        try {
            userId = TokenUtil.getUserId(request);
        } catch (Exception e) {
            // 非登录用户，userId 为 null
        }

        PageResult<ContentWithFilesResponse> pageResult = contentService.getRecommendedContents(userId, pageNum, pageSize);
        return Result.success(pageResult);
    }
    
    // 清除搜索缓存
    @PostMapping("/search/clear-cache")
    public Result<String> clearSearchCache() {
        try {
            // 使用CacheService清除所有搜索缓存
            long count = cacheService.clearAllSearchCache();
            if (count > 0) {
                log.info("已清除{}个搜索缓存", count);
                return Result.success("已成功清除" + count + "个搜索缓存");
            }
            return Result.success("没有找到需要清除的搜索缓存");
        } catch (Exception e) {
            log.error("清除搜索缓存失败", e);
            return Result.error("清除缓存失败: " + e.getMessage());
        }
    }
    
    // 手动将内容重新索引到ElasticSearch
    @PostMapping("/{contentId}/reindex")
    public Result<String> reindexContent(@PathVariable Long contentId, HttpServletRequest request) {
        try {
            // 获取用户角色，确保是管理员操作
            String role = TokenUtil.getRole(request);
            if (!"admin".equals(role)) {
                return Result.error("只有管理员可以执行重新索引操作");
            }
            
            // 获取内容
            Content content = contentMapper.selectById(contentId);
            if (content == null || Boolean.TRUE.equals(content.getIsDeleted())) {
                return Result.error("内容不存在或已被删除");
            }
            
            // 重新索引到ES
            log.info("管理员请求重新索引内容，ID: {}", contentId);
            elasticsearchService.indexContent(content);
            
            // 清除相关缓存
            String contentCacheKey = CONTENT_CACHE_PREFIX + contentId;
            String contentFilesCacheKey = CONTENT_FILES_CACHE_PREFIX + contentId;
            cacheService.deleteCache(contentCacheKey);
            cacheService.deleteCache(contentFilesCacheKey);
            
            // 清除包含此内容的搜索缓存
            long clearedCacheCount = cacheService.clearSearchCacheContainingContent(contentId);
            log.info("已清除{}个包含内容ID: {}的搜索缓存", clearedCacheCount, contentId);
            
            return Result.success("内容已成功重新索引到ElasticSearch");
        } catch (Exception e) {
            log.error("重新索引内容失败，ID: {}, 错误: {}", contentId, e.getMessage(), e);
            return Result.error("重新索引失败: " + e.getMessage());
        }
    }

    /**
     * 完全重建ElasticSearch索引结构 - 管理员专用
     * @param request HTTP请求
     * @return 重建结果
     */
    @PostMapping("/rebuild-index-structure")
    public Result<String> rebuildElasticsearchIndexStructure(HttpServletRequest request) {
        try {
            // 验证管理员权限
            String role = TokenUtil.getRole(request);
            if (!"admin".equals(role)) {
                return Result.error("只有管理员可以执行重建索引结构操作");
            }
            
            // 删除现有索引
            log.info("开始删除并重建索引结构");
            try {
                Request deleteRequest = new Request("DELETE", "/contents");
                RestClient restClient = elasticsearchService.getRestClient();
                restClient.performRequest(deleteRequest);
                log.info("成功删除索引: contents");
            } catch (Exception e) {
                log.warn("删除索引失败（可能不存在）: {}", e.getMessage());
            }
            
            // 创建新的索引结构
            elasticsearchService.createContentIndex();
            
            // 获取所有未删除的内容
            log.info("开始获取所有内容并重新索引");
            List<Content> allContents = contentMapper.selectAllNotDeleted();
            int totalContents = allContents.size();
            log.info("找到{}条未删除的内容需要索引", totalContents);
            
            int successCount = 0;
            int failCount = 0;
            
            // 批量索引所有内容
            for (Content content : allContents) {
                try {
                    // 确保有合适的值
                    if (content.getLikeCount() == null) content.setLikeCount(0);
                    if (content.getCommentCount() == null) content.setCommentCount(0);
                    if (content.getViewCount() == null) content.setViewCount(0);
                    if (content.getIsDeleted() == null) content.setIsDeleted(false);
                    if (content.getCreatedAt() == null) content.setCreatedAt(java.time.LocalDateTime.now());
                    if (content.getUpdatedAt() == null) content.setUpdatedAt(java.time.LocalDateTime.now());
                    
                    elasticsearchService.indexContent(content);
                    successCount++;
                    
                    // 每50条记录输出一次进度
                    if (successCount % 50 == 0) {
                        log.info("已成功索引{}条内容，总进度: {}/{}", 
                                successCount, successCount + failCount, totalContents);
                    }
                } catch (Exception e) {
                    failCount++;
                    log.error("索引内容ID: {}失败: {}", content.getId(), e.getMessage());
                }
            }
            
            // 刷新索引确保所有内容可搜索
            elasticsearchService.refreshContentIndex();
            
            // 清除所有搜索缓存
            cacheService.clearAllSearchCache();
            
            String resultMessage = String.format(
                    "索引结构重建完成。总内容数: %d, 成功: %d, 失败: %d", 
                    totalContents, successCount, failCount);
            log.info(resultMessage);
            
            return Result.success(resultMessage);
        } catch (Exception e) {
            log.error("重建索引结构操作失败", e);
            return Result.error("重建索引结构失败: " + e.getMessage());
        }
    }

    /**
     * 测试搜索API - 显示详细信息
     */
    @GetMapping("/test-search")
    public Result<Map<String, Object>> testSearch(
            @RequestParam String keyword,
            @RequestParam(defaultValue = "1") int pageNum,
            @RequestParam(defaultValue = "10") int pageSize) {
        
        try {
            log.info("执行测试搜索，关键词: {}", keyword);
            
            // 先检查内容是否存在
            List<Content> allContents = contentMapper.selectAllNotDeleted();
            log.info("数据库中共有{}条未删除内容", allContents.size());
            
            // 过滤包含关键词的内容
            List<Content> matchingContents = allContents.stream()
                    .filter(c -> (c.getTitle() != null && c.getTitle().contains(keyword)) ||
                                (c.getDescription() != null && c.getDescription().contains(keyword)))
                    .toList();
            
            log.info("数据库中包含关键词 '{}' 的内容数量: {}", keyword, matchingContents.size());
            
            if (!matchingContents.isEmpty()) {
                matchingContents.forEach(c -> 
                    log.info("匹配内容 - ID: {}, 标题: {}, 描述: {}", c.getId(), c.getTitle(), c.getDescription())
                );
                
                // 检查每个匹配内容是否已被索引
                for (Content c : matchingContents) {
                    boolean indexed = elasticsearchService.isContentIndexed(c.getId());
                    log.info("内容ID: {} 是否已索引: {}", c.getId(), indexed);
                }
            }
            
            // 执行ES搜索
            Result<PageResult<Content>> esResult = elasticsearchService.searchContent(keyword, pageNum, pageSize);
            
            // 组织返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("keyword", keyword);
            result.put("dbTotalCount", allContents.size());
            result.put("dbMatchCount", matchingContents.size());
            result.put("dbMatches", matchingContents.stream()
                    .map(c -> Map.of(
                        "id", c.getId(),
                        "title", c.getTitle(),
                        "description", c.getDescription(),
                        "indexed", elasticsearchService.isContentIndexed(c.getId())
                    ))
                    .toList());
            result.put("esSearchResult", esResult);
            
            return Result.success(result);
        } catch (Exception e) {
            log.error("测试搜索失败", e);
            return Result.error("测试搜索失败: " + e.getMessage());
        }
    }

    /**
     * 重建索引 - 管理员专用
     * @param request HTTP请求
     * @return 重建结果
     */
    @PostMapping("/rebuild-index")
    public Result<String> rebuildElasticsearchIndex(HttpServletRequest request) {
        try {
            // 验证管理员权限
            String role = TokenUtil.getRole(request);
            if (!"admin".equals(role)) {
                return Result.error("只有管理员可以执行重建索引操作");
            }
            
            // 获取所有未删除的内容
            log.info("开始获取所有内容并重新索引");
            List<Content> allContents = contentMapper.selectAllNotDeleted();
            int totalContents = allContents.size();
            log.info("找到{}条未删除的内容需要索引", totalContents);
            
            int successCount = 0;
            int failCount = 0;
            
            // 批量索引所有内容
            for (Content content : allContents) {
                try {
                    // 确保有合适的值
                    if (content.getLikeCount() == null) content.setLikeCount(0);
                    if (content.getCommentCount() == null) content.setCommentCount(0);
                    if (content.getViewCount() == null) content.setViewCount(0);
                    if (content.getIsDeleted() == null) content.setIsDeleted(false);
                    if (content.getCreatedAt() == null) content.setCreatedAt(java.time.LocalDateTime.now());
                    if (content.getUpdatedAt() == null) content.setUpdatedAt(java.time.LocalDateTime.now());
                    
                    elasticsearchService.updateIndexedContent(content);
                    successCount++;
                    
                    // 每50条记录输出一次进度
                    if (successCount % 50 == 0) {
                        log.info("已成功索引{}条内容，总进度: {}/{}", 
                                successCount, successCount + failCount, totalContents);
                    }
                } catch (Exception e) {
                    failCount++;
                    log.error("索引内容ID: {}失败: {}", content.getId(), e.getMessage());
                }
            }
            
            // 刷新索引确保所有内容可搜索
            elasticsearchService.refreshContentIndex();
            
            // 清除所有搜索缓存
            cacheService.clearAllSearchCache();
            
            String resultMessage = String.format(
                    "索引重建完成。总内容数: %d, 成功: %d, 失败: %d", 
                    totalContents, successCount, failCount);
            log.info(resultMessage);
            
            return Result.success(resultMessage);
        } catch (Exception e) {
            log.error("重建索引操作失败", e);
            return Result.error("重建索引失败: " + e.getMessage());
        }
    }
}
